package com.xpec.c4.persistence.amf3byte;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.codec.Codec;
import com.xpec.c4.codec.amf3.Amf3Codec;

/**
 *@author GuoQi E-mail: guoqi@xpec.com.cn
 *@version 创建时间: 2010-5-27下午07:44:39
 */
public class BytesParser implements IParser {

	private static final Log log = LogFactory.getLog(BytesParser.class);

	private static BytesParser bytesParser = null;

	public static BytesParser getInstance() {
		if (bytesParser == null) {
			bytesParser = new BytesParser();
		}

		return bytesParser;
	}

	public File buildWithHeader(Object src, String fileName) {
		File file = null;

		if (fileName != null) {
			Codec codec = new Amf3Codec();
			try {
				file = transferToFileWithHeader(codec.encode(src), fileName);
			} catch (FileNotFoundException e) {
				log.error("file not found error:" + fileName, e);
			} catch (Exception e) {
				log.error("load file error:" + fileName, e);
			}
		}

		return file;
	}
	
	@Override
	public File build(Object src, String fileName) {
		File file = null;

		if (fileName != null) {
			Codec codec = new Amf3Codec();
			try {
				file = transferToFile(codec.encode(src), fileName);
			} catch (FileNotFoundException e) {
				log.error("file not found error:" + fileName, e);
			} catch (Exception e) {
				log.error("load file error:" + fileName, e);
			}
		}

		return file;
	}

	/** 放 bin 檔檔頭資訊的資料結構 */
	public class BytesParserHeadInfo {
		/** 輸出 bin 的電腦名稱 */
		private String hostName;

		/** 輸出 bin 的時間 */
		private String createTime;

		public String getHostName() {
			return hostName;
		}

		public void setHostName(String hostName) {
			this.hostName = hostName;
		}

		public String getCreateTime() {
			return createTime;
		}

		public void setCreateTime(String createTime) {
			this.createTime = createTime;
		}
	}

	public Object parseWithHeader(String fileName,
			BytesParserHeadInfo headerInfo) {
		File file = new File(fileName);

		Codec codec = new Amf3Codec();
		Object obj = null;
		ByteBuffer buff = null;
		try {
			buff = transferToByteBuffer(file);

			// 取得電腦名稱
			int len = buff.getInt();
			byte[] bytes = new byte[len];
			buff.get(bytes, 0, len);
			String hostName = new String(bytes);
			if (headerInfo != null) {
				headerInfo.setHostName(hostName);
			}

			// 取得輸出時間
			len = buff.getInt();
			bytes = new byte[len];
			buff.get(bytes, 0, len);
			String timeString = new String(bytes);
			if (headerInfo != null) {
				headerInfo.setCreateTime(timeString);
			}

			// 取得 object 資料
			len = buff.getInt();
			obj = codec.decode(buff);
		} catch (FileNotFoundException e) {
			log.error("file not found error:" + fileName, e);
		} catch (IOException e) {
			log.error("file io error:" + fileName, e);
		} catch (Exception e) {
			log.error("load file error:" + fileName, e);
		}

		return obj;
	}
	
	@Override
	public Object parse(String fileName) {

		File file = new File(fileName);

		Codec codec = new Amf3Codec();
		Object obj = null;
		try {
			obj = codec.decode(transferToByteBuffer(file));
		} catch (FileNotFoundException e) {
			log.error("file not found error:" + fileName, e);
		} catch (IOException e) {
			log.error("file io error:" + fileName, e);
		} catch (Exception e) {
			log.error("load file error:" + fileName, e);
		}

		return obj;
	}

	/** 一個 int 等於多少個 byte */
	private static final int intByteCount = Integer.SIZE / Byte.SIZE;

	/** 一個 long 等於多少個 byte */
	private static final int longByteCount = Long.SIZE / Byte.SIZE;

	/**
	 * 将ByteBuffer转为File
	 * 
	 * 檔案格式：<br>
	 * length(int) , 電腦名稱(string)<br>
	 * length(int) , 輸出時的時間(string)<br>
	 * length(int) , ObjectBuffer(byte)
	 * 
	 * @param buffer
	 * @param fileName
	 * @return
	 * @throws FileNotFoundException
	 */
	private File transferToFileWithHeader(ByteBuffer buffer, String fileName)
			throws FileNotFoundException {
		// 创建文件
		File file = null;
		if (fileName != null && fileName.length() > 0) {
			// 取得電腦名稱
			InetAddress localMachine = null;
			try {
				localMachine = InetAddress.getLocalHost();
			} catch (UnknownHostException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
			String hostName = localMachine.getHostName();
			byte[] hostNameBytes = hostName.getBytes();

			// 取得目前時間
			long currentTime = System.currentTimeMillis();

			// 設定日期格式
			DateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			String timeString = formatter.format(currentTime);
			byte[] timeStringBytes = timeString.getBytes();

			file = createFileByName(fileName);

			// 创建文件流
			FileOutputStream fileOutputStream = new FileOutputStream(file);

			// 创建通道和缓冲区
			FileChannel fileChannel = fileOutputStream.getChannel();
			
			// 計算所需 buff 空間 (byte)
			int buffSize = intByteCount + hostNameBytes.length;
			buffSize += intByteCount + timeStringBytes.length;
			buffSize += intByteCount + buffer.capacity();

			ByteBuffer buf = ByteBuffer.allocate(buffSize);

			// 將資料放入 buffer
			
			// 寫入電腦名稱
			buf.putInt(hostNameBytes.length);
			buf.put(hostNameBytes);

			// 寫入產生 bin 的時間
			buf.putInt(timeStringBytes.length);
			buf.put(timeStringBytes);

			// 寫入 object 資料
			buf.putInt(buffer.capacity());
			buf.put(buffer.array());

			// 反转此缓冲区
			buf.flip();

			// 写入文件
			try {
				fileChannel.write(buf);
				fileOutputStream.close();
			} catch (IOException e) {
				log.error("file io error:" + fileName, e);
			}
		}

		return file;
	}

	/**
	 * 将ByteBuffer转为File
	 * 
	 * @param buffer
	 * @param fileName
	 * @return
	 * @throws FileNotFoundException
	 */
	private File transferToFile(ByteBuffer buffer, String fileName)
			throws FileNotFoundException {
		// 创建文件
		File file = null;
		if (fileName != null && fileName.length() > 0) {
			file = createFileByName(fileName);

			// 创建文件流
			FileOutputStream fileOutputStream = new FileOutputStream(file);

			// 创建通道和缓冲区
			FileChannel fileChannel = fileOutputStream.getChannel();
			ByteBuffer buf = ByteBuffer.allocate(buffer.capacity());

			// 将字符串转化为字节数组
			buf.put(buffer.array());

			// 反转此缓冲区
			buf.flip();

			// 写入文件
			try {
				fileChannel.write(buf);
				fileOutputStream.close();
			} catch (IOException e) {
				log.error("file io error:" + fileName, e);
			}
		}

		return file;
	}

	/**
	 * File 转成 ByteBuffer
	 * 
	 * @param file
	 * @return ByteBuffer
	 * @throws FileNotFoundException
	 *             文件未找到
	 * @throws IOException
	 *             文件流读取异常
	 */
	private ByteBuffer transferToByteBuffer(File file)
			throws FileNotFoundException, IOException {
		// 创建文件流
		FileInputStream fileInputStream = null;

		fileInputStream = new FileInputStream(file);

		// 创建通道和缓冲区
		FileChannel fileChannel = fileInputStream.getChannel();

		// 缓冲区对象不能通过构造函数生成，可以通过静态方法生成
		int size = fileInputStream.available();
		ByteBuffer buffer = null;
		if (size > 0) {
			buffer = ByteBuffer.allocate(size);

			// 将数据读入到缓冲区
			while (fileChannel.read(buffer) != -1) {
				buffer.flip();
			}

			// 关闭文件流
			fileInputStream.close();
		}
		return buffer;
	}

	/**
	 * 这个函数将我们刚才写入文件的数据读出来，并打印到控制台。 下面补充一个函数，根据文件名字创建一个文件：
	 */
	private File createFileByName(String name) {
		if (name == null || name.length() <= 0) {
			return null;
		}

		File file = new File(name);
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				log.error("file io error:" + name, e);
			}
		}
		return file;
	}
}
